package com.gebogebo.android.pub;

import com.larvalabs.svgandroid.SVG;
import com.larvalabs.svgandroid.SVGParser;

import android.content.Context;
import android.graphics.Canvas;
import android.util.FloatMath;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.View.OnTouchListener;
import android.view.MotionEvent;
import android.view.View;

/**
 * a PUD doodle view which will allow different kinds of transformation on doodle
 * 
 * @author viraj
 */
public class PubEditDoodleView extends View implements OnTouchListener {
    private static final String lg = "doodleView";
    private enum GestureMode {zoom, drag};
    
    private GestureDetector gestureDetector;
    private int iconId;

    //variables used by onTouch callback. if this list grows too big, we can refactor the class in
    //its own file
    private float oldDistance;
    private GestureMode gestureMode = GestureMode.drag;
    
    //values which will be read by view when it is rendered
    private float top = 0;
    private float left = 0;
    private float scale = 1f;

    /**
     * constructor accepting context object
     * 
     * @param context
     */
    public PubEditDoodleView(Context context) {
        super(context);
        gestureDetector = new GestureDetector(context, new PubGestureListener(this));
        this.setOnTouchListener(this);
    }
    
    /* (non-Javadoc)
     * @see android.view.View#onDraw(android.graphics.Canvas)
     */
    public void onDraw(Canvas canvas) {
        if(iconId == 0) {
            //we do not need to draw anything in this case
            Log.i(lg, "nothing to draw");
            super.onDraw(canvas);
            return;
        }
        
        SVG svg = SVGParser.getSVGFromResource(getResources(), iconId);

        canvas.save();
        canvas.translate(left, top);
        canvas.scale(scale, scale);//uniform scaling
        canvas.drawPicture(svg.getPicture());
        canvas.restore();
    }

    /**
     * returns the icon id which is present on this view
     * 
     * @param iconId
     */
    public void setIconId(int iconId) {
        this.iconId = iconId;
    }
    
    /* (non-Javadoc)
     * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
     */
    public boolean onTouch(View v, MotionEvent e) {
        //if there are more than one pointers in the motion event, we process the event as simple gesture
        //detector doesn't detect the pinching gesture
        if(e.getPointerCount() > 1) {
            switch(e.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_POINTER_DOWN:
                    oldDistance = spacing(e);
                    Log.d(lg, "oldDist=" + oldDistance);
                    if (oldDistance > 10f) {
                        gestureMode = GestureMode.zoom;
                    }
                break;
        
                case MotionEvent.ACTION_MOVE:
                    if (gestureMode == GestureMode.zoom) {
                        float newDist = spacing(e);
                        if (newDist > 10f && newDist > oldDistance) {
                            //limiting scaling up to 10 times the original size
                            scale = Math.min(10.0f, scale * newDist / oldDistance);
                        } else if (newDist > 10f && newDist < oldDistance) {
                            //limiting scaling down to half of the original size
                            scale = Math.max(0.5f, scale * newDist / oldDistance);
                        }
                        Log.d(lg, "scale: " + scale);
                        break;
                    }
            }
            //it is important to call view.invalidate() to ensure that real time feedback is shown
            //to the user
            invalidate();
            return true;
        }
        
        //if event has only one pointer, we forward event to gesture detector to detect the
        //event
        gestureDetector.onTouchEvent(e);
        return true;
    }
    
    /**
     * determines spacing between two points on the view which are being dragged. function assumes
     * that motion event has two pointer count. will throw an exception if {@link MotionEvent#getPointerCount()}
     * is less than 2
     * 
     * @param event motion event with two pointers. 
     * @return spacing between two pointers from the event
     */
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return FloatMath.sqrt(x * x + y * y);
    }
    
    /**
     * extends {@link SimpleOnGestureListener} to take the action when doodle view is scrolled
     * 
     * @author viraj
     */
    private class PubGestureListener extends SimpleOnGestureListener {
        private final PubEditDoodleView view;
        
        /**
         * constructor which accepts the doodle view on which gesture is to be detected
         * 
         * @param view doodle view object
         */
        public PubGestureListener(PubEditDoodleView view) {
            this.view = view;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            left = e2.getX();
            top = e2.getY();
            //it is important to call view.invalidate() to ensure that real time feedback is shown
            //to the user
            view.invalidate();
            return true;
        }
        
    }
}


